package providers

import (
	"context"
	"crypto/md5"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
)

// SpaceIoTProvider Space IoT SMS提供商实现
type SpaceIoTProvider struct {
	*BaseProvider
	config *SpaceIoTConfig
}

// SpaceIoTConfig Space IoT配置
type SpaceIoTConfig struct {
	BaseURL string        `json:"base_url"` // API基础URL
	Sign    string        `json:"sign"`     // 签名
	Key     string        `json:"key"`      // 密钥
	Timeout time.Duration `json:"timeout"`  // 超时时间
}

// SpaceIoTSendRequest Space IoT发送请求
type SpaceIoTSendRequest struct {
	AccountName  string `json:"accountName"`  // 账户名称
	Phone        string `json:"phone"`        // 手机号
	Content      string `json:"content"`      // 短信内容
	Timestamp    string `json:"timestamp"`    // 时间戳
	RandomString string `json:"randomString"` // 随机字符串
	Sign         string `json:"sign"`         // 签名
}

// SpaceIoTSendResponse Space IoT发送响应
type SpaceIoTSendResponse struct {
	Code    int    `json:"code"`    // 响应代码
	Message string `json:"message"` // 响应消息
	Data    bool   `json:"data"`    // 响应数据
}

// SpaceIoTQueryRequest Space IoT查询请求
type SpaceIoTQueryRequest struct {
	AccountName  string `json:"accountName"`  // 账户名称
	Phone        string `json:"phone"`        // 手机号
	Timestamp    string `json:"timestamp"`    // 时间戳
	RandomString string `json:"randomString"` // 随机字符串
	Sign         string `json:"sign"`         // 签名
}

// SpaceIoTQueryResponse Space IoT查询响应
type SpaceIoTQueryResponse struct {
	Code    int                      `json:"code"`    // 响应代码
	Message string                   `json:"message"` // 响应消息
	Data    *SpaceIoTQueryResultData `json:"data"`    // 响应数据
}

// SpaceIoTQueryResultData Space IoT查询结果数据
type SpaceIoTQueryResultData struct {
	Status      string `json:"status"`      // 状态
	SentAt      string `json:"sentAt"`      // 发送时间
	DeliveredAt string `json:"deliveredAt"` // 送达时间
	ErrorCode   string `json:"errorCode"`   // 错误代码
	ErrorMsg    string `json:"errorMsg"`    // 错误消息
}

// NewSpaceIoTProvider 创建Space IoT提供商实例
func NewSpaceIoTProvider(config *SpaceIoTConfig) *SpaceIoTProvider {
	provider := &SpaceIoTProvider{
		BaseProvider: &BaseProvider{
			name: "space_iot",
		},
		config: config,
	}

	if config.Timeout > 0 {
		provider.SetTimeout(config.Timeout)
	}

	return provider
}

// SendSMS 发送单条短信
func (p *SpaceIoTProvider) SendSMS(ctx context.Context, req *SendSMSRequest) (*SendSMSResponse, error) {
	// 验证请求参数
	if err := p.ValidateRequest(req); err != nil {
		return nil, err
	}

	// 构建请求
	spaceReq := p.buildSendRequest(req)

	// 发送请求
	start := time.Now()
	resp, err := p.sendRequest(ctx, "/sms/sendByContent", spaceReq)
	latency := time.Since(start)

	if err != nil {
		return nil, p.wrapNetworkError(err, latency)
	}

	// 解析响应
	spaceResp := &SpaceIoTSendResponse{}
	if err := gjson.Unmarshal(resp, spaceResp); err != nil {
		return nil, p.CreateProviderError("PARSE_ERROR", "响应解析失败: "+err.Error(), false)
	}

	// 检查响应状态
	if spaceResp.Code != 0 {
		retryable := p.isRetryableError(spaceResp.Code)
		return nil, p.CreateProviderError(
			strconv.Itoa(spaceResp.Code),
			spaceResp.Message,
			retryable,
		)
	}

	// 构建响应
	response := &SendSMSResponse{
		MessageID:  req.MessageID,
		Status:     "sent",
		ProviderID: req.MessageID, // Space IoT没有返回独立的Provider ID
		Cost:       EstimateCost(req.Content, req.Type),
		SentAt:     time.Now(),
		Metadata:   req.Metadata,
	}

	return response, nil
}

// SendBatchSMS 批量发送短信
func (p *SpaceIoTProvider) SendBatchSMS(ctx context.Context, req *BatchSMSRequest) (*BatchSMSResponse, error) {
	// 验证批量请求参数
	if err := p.ValidateBatchRequest(req); err != nil {
		return nil, err
	}

	startTime := time.Now()
	results := make([]*BatchSMSResult, len(req.Requests))
	successCount := 0
	failedCount := 0
	totalCost := 0.0

	// 逐个发送短信（Space IoT不支持真正的批量发送）
	for i, smsReq := range req.Requests {
		result := &BatchSMSResult{
			Index: i,
			Phone: smsReq.Phone,
		}

		// 发送单条短信
		resp, err := p.SendSMS(ctx, smsReq)
		if err != nil {
			result.Status = "failed"
			if providerErr, ok := err.(*ProviderError); ok {
				result.ErrorCode = providerErr.Code
				result.ErrorMessage = providerErr.Message
			} else {
				result.ErrorCode = "UNKNOWN_ERROR"
				result.ErrorMessage = err.Error()
			}
			failedCount++
		} else {
			result.MessageID = resp.MessageID
			result.ProviderID = resp.ProviderID
			result.Status = resp.Status
			result.Cost = resp.Cost
			result.SentAt = &resp.SentAt
			totalCost += resp.Cost
			successCount++
		}

		results[i] = result
	}

	finishTime := time.Now()

	// 构建批量响应
	response := &BatchSMSResponse{
		BatchID:    req.BatchID,
		Total:      len(req.Requests),
		Success:    successCount,
		Failed:     failedCount,
		Results:    results,
		StartedAt:  startTime,
		FinishedAt: finishTime,
		Cost:       totalCost,
	}

	return response, nil
}

// QuerySMS 查询短信状态
func (p *SpaceIoTProvider) QuerySMS(ctx context.Context, req *QuerySMSRequest) (*QuerySMSResponse, error) {
	if req.Phone == "" {
		return nil, p.CreateProviderError("INVALID_PHONE", "查询短信状态需要提供手机号", false)
	}

	// 构建查询请求
	queryReq := p.buildQueryRequest(req.Phone)

	// 发送查询请求
	resp, err := p.sendRequest(ctx, "/sms/query", queryReq)
	if err != nil {
		return nil, p.wrapNetworkError(err, 0)
	}

	// 解析响应
	queryResp := &SpaceIoTQueryResponse{}
	if err := gjson.Unmarshal(resp, queryResp); err != nil {
		return nil, p.CreateProviderError("PARSE_ERROR", "查询响应解析失败: "+err.Error(), false)
	}

	// 检查响应状态
	if queryResp.Code != 0 {
		retryable := p.isRetryableError(queryResp.Code)
		return nil, p.CreateProviderError(
			strconv.Itoa(queryResp.Code),
			queryResp.Message,
			retryable,
		)
	}

	// 构建查询响应
	response := &QuerySMSResponse{
		MessageID:  req.MessageID,
		ProviderID: req.ProviderID,
		Phone:      req.Phone,
	}

	if queryResp.Data != nil {
		response.Status = queryResp.Data.Status
		response.ErrorCode = queryResp.Data.ErrorCode
		response.ErrorMessage = queryResp.Data.ErrorMsg

		// 解析时间
		if queryResp.Data.SentAt != "" {
			if sentAt, err := time.Parse("2006-01-02 15:04:05", queryResp.Data.SentAt); err == nil {
				response.SentAt = &sentAt
			}
		}
		if queryResp.Data.DeliveredAt != "" {
			if deliveredAt, err := time.Parse("2006-01-02 15:04:05", queryResp.Data.DeliveredAt); err == nil {
				response.DeliveredAt = &deliveredAt
			}
		}
	}

	return response, nil
}

// GetQuota 获取剩余配额
func (p *SpaceIoTProvider) GetQuota(ctx context.Context) (*QuotaResponse, error) {
	// Space IoT API可能不支持配额查询，返回模拟数据
	return &QuotaResponse{
		Total:     10000,
		Used:      0,
		Remaining: 10000,
		ResetAt:   time.Now().Add(24 * time.Hour),
	}, nil
}

// ValidateConfig 验证配置
func (p *SpaceIoTProvider) ValidateConfig() error {
	if p.config == nil {
		return p.CreateProviderError("INVALID_CONFIG", "配置不能为空", false)
	}
	if p.config.BaseURL == "" {
		return p.CreateProviderError("INVALID_BASE_URL", "Base URL不能为空", false)
	}
	if p.config.Sign == "" {
		return p.CreateProviderError("INVALID_SIGN", "签名不能为空", false)
	}
	if p.config.Key == "" {
		return p.CreateProviderError("INVALID_KEY", "密钥不能为空", false)
	}
	return nil
}

// HealthCheck 健康检查
func (p *SpaceIoTProvider) HealthCheck(ctx context.Context) error {
	// 发送一个测试请求来检查服务健康状态
	testReq := &SendSMSRequest{
		Phone:     "+8618888888888", // 测试手机号
		Content:   "健康检查测试",
		Sign:      p.config.Sign,
		MessageID: fmt.Sprintf("health_check_%d", time.Now().Unix()),
	}

	// 构建请求但不实际发送
	spaceReq := p.buildSendRequest(testReq)
	if spaceReq == nil {
		return p.CreateProviderError("HEALTH_CHECK_FAILED", "健康检查请求构建失败", true)
	}

	return nil
}

// buildSendRequest 构建发送请求
func (p *SpaceIoTProvider) buildSendRequest(req *SendSMSRequest) *SpaceIoTSendRequest {
	timestamp := gconv.String(gtime.Now().Unix())
	randomString := strconv.Itoa(rand.Intn(1000))

	// 构建签名
	signStr := p.config.Sign + p.config.Key + timestamp + randomString
	m := md5.New()
	m.Write([]byte(signStr))
	sign := strings.ToLower(fmt.Sprintf("%x", m.Sum(nil)))

	// 构建内容（添加签名前缀）
	content := req.Content
	if req.Sign != "" {
		content = fmt.Sprintf("【%s】%s", req.Sign, content)
	} else {
		content = fmt.Sprintf("【%s】%s", p.config.Sign, content)
	}

	return &SpaceIoTSendRequest{
		AccountName:  p.config.Sign,
		Phone:        req.Phone,
		Content:      content,
		Timestamp:    timestamp,
		RandomString: randomString,
		Sign:         sign,
	}
}

// buildQueryRequest 构建查询请求
func (p *SpaceIoTProvider) buildQueryRequest(phone string) *SpaceIoTQueryRequest {
	timestamp := gconv.String(gtime.Now().Unix())
	randomString := strconv.Itoa(rand.Intn(1000))

	// 构建签名
	signStr := p.config.Sign + p.config.Key + timestamp + randomString
	m := md5.New()
	m.Write([]byte(signStr))
	sign := strings.ToLower(fmt.Sprintf("%x", m.Sum(nil)))

	return &SpaceIoTQueryRequest{
		AccountName:  p.config.Sign,
		Phone:        phone,
		Timestamp:    timestamp,
		RandomString: randomString,
		Sign:         sign,
	}
}

// sendRequest 发送HTTP请求
func (p *SpaceIoTProvider) sendRequest(ctx context.Context, endpoint string, body interface{}) ([]byte, error) {
	url := p.config.BaseURL + endpoint

	// 创建HTTP客户端
	client := g.Client().Discovery(nil).ContentJson().Timeout(p.GetTimeout())

	// 发送请求
	resp, err := client.Post(ctx, url, body)
	if err != nil {
		return nil, err
	}
	defer resp.Close()

	// 读取响应
	return resp.ReadAll(), nil
}

// wrapNetworkError 包装网络错误
func (p *SpaceIoTProvider) wrapNetworkError(err error, latency time.Duration) error {
	retryable := true
	code := "NETWORK_ERROR"
	message := "网络请求失败: " + err.Error()

	// 根据错误类型判断是否可重试
	if strings.Contains(err.Error(), "timeout") {
		code = "TIMEOUT"
		message = "请求超时"
	} else if strings.Contains(err.Error(), "connection refused") {
		code = "CONNECTION_REFUSED"
		message = "连接被拒绝"
	} else if strings.Contains(err.Error(), "no such host") {
		code = "DNS_ERROR"
		message = "DNS解析失败"
		retryable = false
	}

	return p.CreateProviderError(code, message, retryable)
}

// isRetryableError 判断错误是否可重试
func (p *SpaceIoTProvider) isRetryableError(code int) bool {
	// 根据Space IoT的错误代码判断是否可重试
	switch code {
	case 0:
		return false // 成功
	case 1001:
		return false // 参数错误
	case 1002:
		return false // 签名错误
	case 1003:
		return false // 账户不存在
	case 1004:
		return false // 余额不足
	case 1005:
		return true // 系统繁忙
	case 1006:
		return false // 手机号格式错误
	case 1007:
		return false // 内容包含敏感词
	case 1008:
		return true // 发送频率过快
	case 1009:
		return false // IP不在白名单
	case 1010:
		return true // 网关错误
	default:
		return true // 未知错误，默认可重试
	}
}